#ifndef __FLOAT__
#define __FLOAT__

#include <iostream>
#include <string>
#include <cassert>

typedef char byte;

using namespace std;

class Float{

	public:

		/**
		 * Constructores
		 */
		Float();
		Float(const string&);

		bool operator== (const Float&);

		/**
		 * operadores aritmeticos
		 */
		friend Float operator+(const Float&, const Float&);
		Float operator*(const Float&);
		void operator=(const Float&);

		string mostrar() const;

	private:
        static void sumaMismoSigno(const Float&, const Float&, Float&);
        static void sumaDistitnoSigno(const Float&, const Float&, Float&);

		long long int precision;
		// mantisa[0] es la parte mas significativa (big-indian)
		char* mantisa;
		long long int exponente;
		bool signo;

};


Float::Float(){
	precision = 0;
	mantisa = NULL;
	exponente = 0;
	signo = false;
}

/**
 * Requiere que el numero tenga una coma, tenga un digito entero(puede ser 0) y que tenga sentido o que sea el '0'
 */
Float::Float(const string& num) {
    cout << num << endl;
    if(num.size() == 1 && num[0] == '0') {
        signo = false;
        precision = 0;
        mantisa = new byte[1];
        exponente = 0;
        return;
    }
    //sino es cualquier otro numero
    int pos=0;
    if(num[pos] == '-') {
        signo=true;
        pos++;
    } else {
        signo = false;
    }
    //me qudo con lo entero en "entero"
    string entero = "";
    while(num[pos] == '0') {
        pos++;
    }
    while(num[pos] != ',') {
        entero += num[pos];
        pos++;
    }
    //me quedo con lo factal en "decimal"
    string decimal = "";
    pos = num.size()-1;
    while(num[pos] == '0')
        pos--;
    while(num[pos] != ',') {
        decimal = num[pos] + decimal;
        pos--;
    }
    //hasta aca esta en entero y el decimal por separados
    //se calcula exponente
    if(entero.size() > 0) {
        exponente = entero.size();
    } else {
        exponente=0;
        while(decimal[exponente] == '0')
            exponente++;
        decimal = decimal.substr(exponente);
        exponente=exponente*(-1);
    }
    //hasta aca ya esta el exponente
    string todo = entero+decimal;
    precision = todo.size();
    mantisa = new byte[precision];
    for(pos=0;pos<precision;pos++)
        mantisa[pos] = todo[pos]-'0';
}

Float operator+(const Float& f1, const Float& f2) {
    Float ret;
    if(f1.signo == f2.signo)
        Float::sumaMismoSigno(f1,f2,ret);
    else
        sumaDistitnoSigno(f1,f2,ret);
    return ret;
}
void Float::sumaMismoSigno(const Float& f1, const Float& f2, Float& ret) {
    assert(f1.signo == f2.signo);
    ret.signo = f1.signo;
    if(f1.exponente == f2.exponente) {
        ret.exponente = f1.exponente;
        int minPrecision; //dese donde sumar
        if(f1.precision == f2.precision) {
            ret.precision = f1.precision;
            ret.mantisa = new byte[ret.precision];
            minPrecision = f1.precision;
        } else {
            if(f1.precision < f2.precision) {
                ret.precision = f2.precision;
                ret.mantisa = new byte[ret.precision];
                minPrecision = f1.precision;
                for(int i=minPrecision;i<f2.precision;i++)
                    ret.mantisa[i] = f2.mantisa[i];
            } else { //f2.presicion > f1.presicion
                ret.precision = f1.precision;
                ret.mantisa = new byte[ret.precision];
                minPrecision = f2.precision;
                for(int i=minPrecision;i<f1.precision;i++)
                    ret.mantisa[i] = f1.mantisa[i];
            }
        }
        bool hayCarry = false;
        for(int i=minPrecision-1;i>=0;i--) {
            byte aux = f1.mantisa[i] + f2.mantisa[i] + (hayCarry?1:0);
            hayCarry = aux>9;
            aux=aux%10;
            ret.mantisa[i] = aux;
        }
    } else {//los exponentes son diferentes
        if(f1.exponente < f2.exponente) {
            Float aux;
            aux = f1;
            long long int dif = f2.exponente - f1.exponente;
            long long int nuevaP = aux.precision + dif;
            aux.exponente = f2.exponente;
            byte *mantisaAux =  new byte[nuevaP];
            for(int i=0;i<dif;i++)
                mantisaAux[i] = 0;
            for(int i=dif;i<nuevaP;i++)
                mantisaAux[i] = aux.mantisa[i-dif];
            delete [] aux.mantisa;
            aux.mantisa = mantisaAux;
            aux.precision = nuevaP;
            aux.exponente = f2.exponente;
            Float::sumaMismoSigno(aux,f2,ret);
        } else {
            Float aux;
            aux = f2;
            long long int dif = f1.exponente - f2.exponente;
            long long int nuevaP = aux.precision + dif;
            aux.exponente = f1.exponente;
            byte *mantisaAux =  new byte[nuevaP];
            for(int i=0;i<dif;i++)
                mantisaAux[i] = 0;
            for(int i=dif;i<nuevaP;i++)
                mantisaAux[i] = aux.mantisa[i-dif];
            delete [] aux.mantisa;
            aux.mantisa = mantisaAux;
            aux.precision = nuevaP;
            aux.exponente = f1.exponente;
            Float::sumaMismoSigno(f1,aux,ret);
        }
    }
    if(ret.mantisa[0] < f1.mantisa[0] && ret.mantisa[0] < f2.mantisa[0]) {
        byte *newMantisa = new byte[ret.precision+1];
        for(int i=0;i<ret.precision;i++)
                    newMantisa[i+1] = ret.mantisa[i];
        newMantisa[0] = 1;
        delete [] ret.mantisa;
        ret.mantisa = newMantisa;
        ret.exponente = ret.exponente + 1;
        cout << "P: " << ret.precision << endl;
        ret.precision = ret.precision+1;
        cout << "P: " << ret.precision << endl;
        while(ret.mantisa[ret.precision-1] == 0) {
            ret.precision--;
        }
    }
    while(ret.mantisa[ret.precision-1] == 0 && ret.precision > 0 ){
            ret.precision--;
            cout << "PA: " << ret.precision << endl;
    }
}

static void sumaDistitnoSigno(const Float&, const Float&, Float&) {
    assert(f1.signo != f2.signo);
    ret.signo = f1.signo;
    if(f1.exponente == f2.exponente) {
        /*ret.exponente = f1.exponente;
        int minPrecision; //dese donde sumar
        if(f1.precision == f2.precision) {
            ret.precision = f1.precision;
            ret.mantisa = new byte[ret.precision];
            minPrecision = f1.precision;
        } else {
            if(f1.precision < f2.precision) {
                ret.precision = f2.precision;
                ret.mantisa = new byte[ret.precision];
                minPrecision = f1.precision;
                for(int i=minPrecision;i<f2.precision;i++)
                    ret.mantisa[i] = f2.mantisa[i];
            } else { //f2.presicion > f1.presicion
                ret.precision = f1.precision;
                ret.mantisa = new byte[ret.precision];
                minPrecision = f2.precision;
                for(int i=minPrecision;i<f1.precision;i++)
                    ret.mantisa[i] = f1.mantisa[i];
            }
        }
        bool hayCarry = false;
        for(int i=minPrecision-1;i>=0;i--) {
            byte aux = f1.mantisa[i] + f2.mantisa[i] + (hayCarry?1:0);
            hayCarry = aux>9;
            aux=aux%10;
            ret.mantisa[i] = aux;
        }*/
    } else {//los exponentes son diferentes
        if(f1.exponente < f2.exponente) {
            Float aux;
            aux = f1;
            long long int dif = f2.exponente - f1.exponente;
            long long int nuevaP = aux.precision + dif;
            aux.exponente = f2.exponente;
            byte *mantisaAux =  new byte[nuevaP];
            for(int i=0;i<dif;i++)
                mantisaAux[i] = 0;
            for(int i=dif;i<nuevaP;i++)
                mantisaAux[i] = aux.mantisa[i-dif];
            delete [] aux.mantisa;
            aux.mantisa = mantisaAux;
            aux.precision = nuevaP;
            aux.exponente = f2.exponente;
            Float::sumaDistitnoSigno(aux,f2,ret);
        } else {
            Float aux;
            aux = f2;
            long long int dif = f1.exponente - f2.exponente;
            long long int nuevaP = aux.precision + dif;
            aux.exponente = f1.exponente;
            byte *mantisaAux =  new byte[nuevaP];
            for(int i=0;i<dif;i++)
                mantisaAux[i] = 0;
            for(int i=dif;i<nuevaP;i++)
                mantisaAux[i] = aux.mantisa[i-dif];
            delete [] aux.mantisa;
            aux.mantisa = mantisaAux;
            aux.precision = nuevaP;
            aux.exponente = f1.exponente;
            Float::sumaDistitnoSigno(f1,aux,ret);
        }
    }
}

void Float::operator=(const Float& f) {
    signo = f.signo;
    exponente = f.exponente;
    precision = f.precision;
    if(!&mantisa == NULL)
        delete [] mantisa;
    mantisa = new byte[precision];
    for(int i=0;i<precision;i++)
        mantisa[i] = f.mantisa[i];
}


/** NI VAN EN EL TP CAPAZ **/
ostream& operator<<(ostream& out, const Float& f) {
    out << f.mostrar() << endl;
    return out;
}

string Float::mostrar() const {
    string result = "";
    if(signo)
        cout << "-";
//        result += "-";
    cout << "0,";
    for(int i=0;i<precision;i++)
        cout << ((int)mantisa[i]);
//        result+= (mantisa[i]+'0');
    cout << " *10^ ";
//    result+= " *10^ ";
//    long long int ex = exponente;
    if(exponente < 0) {
//        result+="-";
//        ex*=(-1);

    }
    cout << exponente << endl;
//    result+= ex;
    return result;
}

#endif

